#pragma once

#include <iostream>

#include <unistd.h>
#include <sys/wait.h>
#include <fcntl.h>
#include "../common/Util.hpp"
#include "../common/Log.hpp"
namespace ns_compiler
{

    //引入公共方法，主要是路径处理方法
    using namespace ns_Util;
    using namespace ns_Log;
    class Compiler{

        public:
        Compiler()
        {

        }
        ~Compiler()
        {

        }

        //传入需要编译的C++代码文件,不需要后缀
        //本项目让其放在当前目录的temp目录下，每个cpp文件生成对应的.exe
        //同时，我们还会输出错误信息，那么再加一个，.error文件
        static bool  Compile(const std::string& file_name)
        {
            pid_t forkId  =fork();
            if(forkId==0)
            {
                //子进程
                //调用编译器，完成编译，要使用进程程序替换
                //同时我们要得到编译信息，那么就需要使用重定向，
                //先做重定向，再做进程替换

                umask(0);
                int fd = open(TempPathUtil::FormError(file_name).c_str(),O_WRONLY | O_CREAT | O_TRUNC,0644);
                if(fd<0)
                {
                    std::cout<<lg(MsgLevel::Warning,__FILE__,__LINE__)<<"没有成功形成.error文件\n";
                    exit(2);
                }
                //编译器在编译失败时，会向标准错误写入，重定向写入到错误文件
                dup2(fd,2);

                execlp("/usr/bin/g++-12", "g++","-o",TempPathUtil::FormExe(file_name).c_str(),TempPathUtil::FormSrc(file_name).c_str(),"-std=c++23",nullptr/*空串结尾是必须的*/);
                //如果程序替换失败，就终止这个进程
                std::cerr<<lg(MsgLevel::Error,__FILE__,__LINE__)<<"启动g++编译器失败，可能是未安装或者是或者找不到\n";
                exit(1);
            }
            else if(forkId>0)
            {
                waitpid(forkId,nullptr,0);
                //编译是否成功，可以通过g++的返回值判断。但是那样做还要排除时进程程序替换失败的可能性，同时也要查询g++编译器返回值

                //因此通过是否形成一个对应的可执行文件
                if(FileUtil:: IsExistFile(TempPathUtil::FormExe(file_name)))
                {
                    std::cout<<lg(Info,__FILE__,__LINE__)<<"编译成功\n";
                    return 1;
                }
            }
            else if(forkId<0)
            {
                std::cerr<<lg(MsgLevel::Error,__FILE__,__LINE__)+"内部错误失败\n";
                //进程创建出错,编译一定失败
                return false;
            }
            //走到这里，必然时时编译失败了
            std::cerr<<lg(MsgLevel::Error,__FILE__,__LINE__)<<"编译失败,没有形成可执行程序\n";
            return 0;
        }
    };
}